﻿#if !LITE

using System;
using System.Collections;
using System.Text;
using System.IO;

using iTextSharp.text;
using iTextSharp.text.pdf;

namespace iPdf
{
    abstract class OfficeConverter
    {
        #region Fields
        protected ArrayList hyperlinks;
        protected string savedFileName;

        protected ArrayList bookmarks;

        protected static OfficeToPdfOption convertOption;
        protected static DestinationItem workItem;
        #endregion

        #region Properties
        public static OfficeToPdfOption ConvertOption
        {
            set
            {
                convertOption = value;
            }
        }

        public static DestinationItem WorkItem
        {
            set
            {
                workItem = value;
            }
        }

        public abstract FileFormat Format
        {
            get;
        }

        public abstract string ApplicationName
        {
            get;
        }
        #endregion

        #region Helper Methods
        protected static bool CheckCoordinates(float startX, float endX, float startY, float endY)
        {
            if (startX < 0 || endX < 0 || startX >= endX ||
                startY < 0 || endY < 0 || startY >= endY)
            {
                return false;
            }

            return true;
        }

        protected static Rectangle CreateRectangle(float startX, float endX,
                                float startY, float endY, PageSetup pageSetup)
        {
            return CreateRectangle(startX, endX, startY, endY, pageSetup, 0);
        }

        protected static Rectangle CreateRectangle(float startX, float endX,
                                float startY, float endY, PageSetup pageSetup,
                                 float customVerticalOffset)
        {
            if (CheckCoordinates(startX, endX, startY, endY) == false)
            {
                return null;
            }

            CoordinateConverter.ConvertHorizontalCoordinate(ref startX, pageSetup);
            CoordinateConverter.ConvertHorizontalCoordinate(ref endX, pageSetup);
            CoordinateConverter.ConvertVerticalCoordinate(ref startY, pageSetup, customVerticalOffset);
            CoordinateConverter.ConvertVerticalCoordinate(ref endY, pageSetup, customVerticalOffset);

            return new Rectangle(startX, endY, endX, startY);
        }

        protected BookmarkNode CreateBookmarkByPageNo(int pageNo, string title, int level, PageSetup pageSetup)
        {
            AbsolutePosition position = new AbsolutePosition(0, 0, pageNo);
            return CreateBookmarkByPosition(position, title, level, pageSetup);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "System.Int32.ToString")]
        protected BookmarkNode CreateBookmarkByPosition(AbsolutePosition position, string title, int level, PageSetup pageSetup)
        {
            if (bookmarks == null)
            {
                bookmarks = new ArrayList();
            }

            //transfer to PDF creator's coordinate system
            position.Adjust(pageSetup, Global.BookmarkSpecificOffset);

            Hashtable node = new Hashtable();
            node["Title"] = title;
            node["Action"] = "GoTo";
            int verticalPosition = (int)position.Y;
            string page = position.PageNo.ToString() + " FitH " + verticalPosition;
            node["Page"] = page;
            node["Level"] =  level;
            return new BookmarkNode(node);
        }

        protected static float GetTotalFontSize(TataFont font)
        {
            return font.Size * font.Scaling + 2 * font.Spacing;
        }
        #endregion

        private void CreatePDF()
        {
            Global.CheckUserCancellation();

            OpenFile();

            savedFileName = PdfCreatorOption.ChangeAutosaveOptions(Global.PdfExt, convertOption.Format);

            //for some files and for unknown reason of Microsoft Word, we need to sleep for 1 second
            //cause if we call PrintOut right away, some files can't be printed
            Helper.Sleep(Global.RestTime);

            try
            {
                PrintOut();

                Global.CheckUserCancellation();

                if (convertOption.Bookmark)
                {
                    ExtractBookmarks();
                }

                Global.CheckUserCancellation();

                if (convertOption.Hyperlink)
                {
                    ExtractHyperlinks();
                }

                if (!WaitForPrintingToFinish())
                {
                    throw new TataException("Unable to print the file " + workItem.Source);
                }
            }
            finally
            {
                CloseFile();
                PdfCreator.DeleteCustomPaperSize();
            }
        }

        //check to see if the printing is over
        protected virtual bool WaitForPrintingToFinish()
        {
            return PdfCreator.WaitForPrintingToFinish(savedFileName);
        }

        private void Merge()
        {
            if ((bookmarks == null || bookmarks.Count == 0) &&
                (hyperlinks == null || hyperlinks.Count == 0) &&
                convertOption.Navigator == false && Helper.IsAscii(workItem.Source) 
                && Helper.IsAscii(workItem.Destination) && 
                Path.GetFileNameWithoutExtension(workItem.Source).Equals(
                Path.GetFileNameWithoutExtension(workItem.Destination), 
                StringComparison.OrdinalIgnoreCase)
                )
            {
                Helper.CopyFile(savedFileName, workItem.Destination);
                NullfyObjects();
                Helper.CollectGarbage();
            }

            PdfReader reader = null;
            FileStream outputStream = null;
            PdfStamper stamper = null;
            FileStream fs = null;
            try
            {
                fs = File.OpenRead(savedFileName);
                reader = new PdfReader(fs);
                reader.ConsolidateNamedDestinations();

                outputStream = Helper.OpenWrite(workItem.Destination);

                stamper = new PdfStamper(reader, outputStream);
                
                if (convertOption.Bookmark && bookmarks != null && bookmarks.Count > 0)
                {
                    stamper.ViewerPreferences = reader.SimpleViewerPreferences |
                                        PdfWriter.PageModeUseOutlines;
                    stamper.Outlines = bookmarks;
                }

                if (convertOption.Hyperlink && hyperlinks != null && hyperlinks.Count > 0)
                {
                    foreach (Hyperlink link in hyperlinks)
                    {
                        link.AddAnnotation(stamper);
                    }
                }

                if (convertOption.Navigator)
                {
                    Navigator navigator = new Navigator();
                    navigator.AttachToDocument(stamper);
                }

                //address the issue that PDFCreator can't handle Non-ASCII characters correctly
                Hashtable info = reader.Info;
                info["Title"] = Path.GetFileName( workItem.Destination );
                stamper.MoreInfo = info;
            }
            finally
            {
                SharpHelper.ClosePdf(stamper, outputStream, reader, fs, true);

                NullfyObjects();
            }
        }

        protected abstract void OpenFile();

        protected abstract void CloseFile();

        protected abstract void OpenApplication();

        public abstract void CloseApplication();

        protected abstract void PrintOut();

        public void Convert()
        {
            OpenApplication();

            NullfyObjects();

            CreatePDF();

            Merge();
        }

        protected virtual void ExtractBookmarks()
        {
        }

        protected virtual void ExtractHyperlinks()
        {
        }

        private void NullfyObjects()
        {
            hyperlinks = null;
            bookmarks = null;
        }
    }
}

#endif